﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.ETL.Properties;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class FuzzyLinkComponent:WorkflowComponentBase
    {
        #region props

        private FuzzyLinkInstruction _Instruction;
        public override InstructionBase Instruction
        {
            get { return _Instruction; }
            set { _Instruction = (FuzzyLinkInstruction) value; }
        }

        private FuzzyLinkOutput _Output;
        public override ResultBase Output
        {
            get { return _Output; }
            set { _Output = (FuzzyLinkOutput) value; }
        }

        /// <summary></summary>
        public DataProviderType SrcDbProvider1
        {
            get
            {
                return this._Instruction.SrcDbProvider1;
            }
            set
            {
                this._Instruction.SrcDbProvider1 = value;
            }
        }

        /// <summary></summary>
        public DataProviderType SrcDbProvider2
        {
            get
            {
                return this._Instruction.SrcDbProvider2;
            }
            set
            {
                this._Instruction.SrcDbProvider2 = value;
            }
        }

        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get
            {
                return this._Instruction.TgtDbProvider;
            }
            set
            {
                this._Instruction.TgtDbProvider = value;
            }
        }

        /// <summary></summary>
        public string SrcConnStr1
        {
            get
            {
                return this._Instruction.SrcConnStr1;
            }
            set
            {
                this._Instruction.SrcConnStr1 = value;
            }
        }

        /// <summary></summary>
        public string SrcConnStr2
        {
            get
            {
                return this._Instruction.SrcConnStr2;
            }
            set
            {
                this._Instruction.SrcConnStr2 = value;
            }
        }

        /// <summary></summary>
        public string TgtConnStr
        {
            get
            {
                return this._Instruction.TgtConnStr;
            }
            set
            {
                this._Instruction.TgtConnStr = value;
            }
        }

        /// <summary></summary>
        public string SrcSql1
        {
            get
            {
                return this._Instruction.SrcSql1;
            }
            set
            {
                this._Instruction.SrcSql1 = value;
            }
        }

        /// <summary></summary>
        public string SrcSql2
        {
            get
            {
                return this._Instruction.SrcSql2;
            }
            set
            {
                this._Instruction.SrcSql2 = value;
            }
        }

        /// <summary></summary>
        public string SrcKeyField1
        {
            get
            {
                return this._Instruction.SrcKeyField1;
            }
            set
            {
                this._Instruction.SrcKeyField1 = value;
            }
        }

        /// <summary></summary>
        public string SrcKeyField2
        {
            get
            {
                return this._Instruction.SrcKeyField2;
            }
            set
            {
                this._Instruction.SrcKeyField2 = value;
            }
        }

        /// <summary></summary>
        public string SrcField1
        {
            get
            {
                return this._Instruction.SrcField1;
            }
            set
            {
                this._Instruction.SrcField1 = value;
            }
        }

        /// <summary></summary>
        public string SrcField2
        {
            get
            {
                return this._Instruction.SrcField2;
            }
            set
            {
                this._Instruction.SrcField2 = value;
            }
        }

        /// <summary></summary>
        public string ComparerAssemblyName
        {
            get
            {
                return this._Instruction.ComparerAssemblyName;
            }
            set
            {
                this._Instruction.ComparerAssemblyName = value;
            }
        }

        /// <summary></summary>
        public string ComparerTypeName
        {
            get
            {
                return this._Instruction.ComparerTypeName;
            }
            set
            {
                this._Instruction.ComparerTypeName = value;
            }
        }

        /// <summary></summary>
        public double FieldSimilarityScoreThreshold
        {
            get
            {
                return this._Instruction.FieldSimilarityScoreThreshold;
            }
            set
            {
                this._Instruction.FieldSimilarityScoreThreshold = value;
            }
        }

        /// <summary></summary>
        public string TgtTableName
        {
            get
            {
                return this._Instruction.TgtTableName;
            }
            set
            {
                this._Instruction.TgtTableName = value;
            }
        }

        /// <summary></summary>
        public Dictionary<string, string> Src1TgtFieldMappings
        {
            get
            {
                return this._Instruction.Src1TgtFieldMappings;
            }
            set
            {
                this._Instruction.Src1TgtFieldMappings = value;
            }
        }

        /// <summary></summary>
        public Dictionary<string, string> Src2TgtFieldMappings
        {
            get
            {
                return this._Instruction.Src2TgtFieldMappings;
            }
            set
            {
                this._Instruction.Src2TgtFieldMappings = value;
            }
        }

        /// <summary></summary>
        public Dictionary<string, string> Src1_Src2_Joinings
        {
            get
            {
                return this._Instruction.Src1_Src2_Joinings;
            }
            set
            {
                this._Instruction.Src1_Src2_Joinings = value;
            }
        }

        /// <summary></summary>
        public string LinkScoreFieldInTargetTable
        {
            get
            {
                return this._Instruction.LinkScoreFieldInTargetTable;
            }
            set
            {
                this._Instruction.LinkScoreFieldInTargetTable = value;
            }
        }

        /// <summary></summary>
        public bool SkipUpdateExistingData
        {
            get
            {
                return this._Instruction.SkipUpdateExistingData;
            }
            set
            {
                this._Instruction.SkipUpdateExistingData = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public FuzzyLinkComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.ETL.ToString();
            this.ComponentName = "Fuzzy Link";
            this.Description = "Link data when specified fields meets threshold using specified comparer";
            this.ComponentIcon = Resources.dtspipeline_2_106;
            this.ComponentImage = Resources.INTERNET_JPG;

            this._Instruction = new FuzzyLinkInstruction(
                this.ComponentID, Guid.Empty,
                DataProviderType.MSSQL, string.Empty, string.Empty, string.Empty, string.Empty,
                DataProviderType.MSSQL, string.Empty, string.Empty, string.Empty, string.Empty,
                DataProviderType.MSSQL, string.Empty, string.Empty,
                new Dictionary<string, string>(), new Dictionary<string, string>(),
                string.Empty, string.Empty, 1.0, 
                new Dictionary<string,string>(), string.Empty, true);
            this._Output = new FuzzyLinkOutput(this.ComponentID, Guid.Empty,
                                               0, 0, 0);
        }
        #endregion

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                FuzzyLinkComponent component = base.Instantiate(xNode) as FuzzyLinkComponent;

                component.SrcDbProvider1 =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(
                                  xNode, "SrcDbProvider1",
                                  ((int)DataProviderType.MSSQL).ToString()));
                component.SrcConnStr1 = XmlDataUtil.GetAttributeValue(xNode, "SrcConnStr1", "");
                component.SrcSql1 = XmlDataUtil.GetAttributeValue(xNode, "SrcSql1", "");
                component.SrcKeyField1 = XmlDataUtil.GetAttributeValue(xNode, "SrcKeyField1", "");
                component.SrcField1 = XmlDataUtil.GetAttributeValue(xNode, "SrcField1", "");

                component.SrcDbProvider2 =
                    (DataProviderType)int.Parse(
                                           XmlDataUtil.GetAttributeValue(
                                               xNode, "SrcDbProvider2", ((int)DataProviderType.MSSQL).ToString()));
                component.SrcConnStr2 = XmlDataUtil.GetAttributeValue(xNode, "SrcConnStr2", "");
                component.SrcSql2 = XmlDataUtil.GetAttributeValue(xNode, "SrcSql2", "");
                component.SrcKeyField2 = XmlDataUtil.GetAttributeValue(xNode, "SrcKeyField2", "");
                component.SrcField2 = XmlDataUtil.GetAttributeValue(xNode, "SrcField2", "");

                component.TgtDbProvider =
                    (DataProviderType)int.Parse(
                                           XmlDataUtil.GetAttributeValue(xNode, "TgtDbProvider",
                                                                         ((int)DataProviderType.MSSQL).ToString()));
                component.TgtConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                component.TgtTableName = XmlDataUtil.GetAttributeValue(xNode, "TgtTableName", "");

                component.ComparerAssemblyName = XmlDataUtil.GetAttributeValue(xNode, "ComparerAssemblyName", "");
                component.ComparerTypeName = XmlDataUtil.GetAttributeValue(xNode, "ComparerTypeName", "");
                component.FieldSimilarityScoreThreshold =
                    double.Parse(XmlDataUtil.GetAttributeValue(xNode, "SimilarityThreshold", "1.0"));

                XmlNodeList src1MappingNodes = xNode.SelectNodes("Src1TgtFieldMappings/FieldMapping");
                if (src1MappingNodes != null && src1MappingNodes.Count > 0)
                {
                    component.Src1TgtFieldMappings = new Dictionary<string, string>();
                    foreach (XmlNode mappingNode in src1MappingNodes)
                    {
                        string srcField = XmlDataUtil.GetAttributeValue(mappingNode, "SrcField", "");
                        string tgtField = XmlDataUtil.GetAttributeValue(mappingNode, "TgtField", "");
                        component.Src1TgtFieldMappings.Add(srcField, tgtField);
                    }
                }

                XmlNodeList src2MappingNodes = xNode.SelectNodes("Src2TgtFieldMappings/FieldMapping");
                if (src2MappingNodes != null && src2MappingNodes.Count > 0)
                {
                    component.Src2TgtFieldMappings = new Dictionary<string, string>();
                    foreach (XmlNode mappingNode in src2MappingNodes)
                    {
                        string srcField = XmlDataUtil.GetAttributeValue(mappingNode, "SrcField", "");
                        string tgtField = XmlDataUtil.GetAttributeValue(mappingNode, "TgtField", "");
                        component.Src2TgtFieldMappings.Add(srcField, tgtField);
                    }
                }

                XmlNodeList srcFieldJoiningNodes = xNode.SelectNodes("SrcJoinings/SrcJoining");
                if (srcFieldJoiningNodes != null && srcFieldJoiningNodes.Count > 0)
                {
                    component.Src1_Src2_Joinings = new Dictionary<string, string>();
                    foreach (XmlNode joiningNode in srcFieldJoiningNodes)
                    {
                        string src1Field = XmlDataUtil.GetAttributeValue(joiningNode, "SrcField1", "");
                        string src2Field = XmlDataUtil.GetAttributeValue(joiningNode, "SrcField2", "");
                        component.Src1_Src2_Joinings.Add(src1Field, src2Field);
                    }
                }

                component.LinkScoreFieldInTargetTable = XmlDataUtil.GetAttributeValue(xNode, "LinkScoreField", "");

                component.SkipUpdateExistingData =
                    bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "SkipUpdateExistingData", true.ToString()));

                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate email: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcDbProvider1", ((int)this.SrcDbProvider1).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcConnStr1", this.SrcConnStr1);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcSql1", this.SrcSql1);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcKeyField1", this.SrcKeyField1);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcField1", this.SrcField1);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcDbProvider2", ((int)this.SrcDbProvider2).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcConnStr2", this.SrcConnStr2);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcSql2", this.SrcSql2);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcKeyField2", this.SrcKeyField2);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcField2", this.SrcField2);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtDbProvider", ((int)this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtTableName", this.TgtTableName);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComparerAssemblyName", this.ComparerAssemblyName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComparerTypeName", this.ComparerTypeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SimilarityThreshold",
                                        this.FieldSimilarityScoreThreshold.ToString());

            if (this.Src1TgtFieldMappings != null && this.Src1TgtFieldMappings.Count > 0)
            {
                XmlNode mappingRootNode1 = XmlDataUtil.AddElement(ref xDoc, xNode, "Src1TgtFieldMappings");
                foreach (string srcFieldName in this.Src1TgtFieldMappings.Keys)
                {
                    XmlNode mappingNode = XmlDataUtil.AddElement(ref xDoc, mappingRootNode1, "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode, "SrcField", srcFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode, "TgtField",
                                                this.Src1TgtFieldMappings[srcFieldName]);
                }
            }

            if (this.Src2TgtFieldMappings != null && this.Src2TgtFieldMappings.Count > 0)
            {
                XmlNode mappingRoot2 = XmlDataUtil.AddElement(ref xDoc, xNode, "Src2TgtFieldMappings");
                foreach (string srcFieldName in this.Src2TgtFieldMappings.Keys)
                {
                    XmlNode mappingNode = XmlDataUtil.AddElement(ref xDoc, mappingRoot2, "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode, "SrcField", srcFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode, "TgtField",
                                                this.Src2TgtFieldMappings[srcFieldName]);
                }
            }

            if (this.Src1_Src2_Joinings != null && this.Src1_Src2_Joinings.Count > 0)
            {
                XmlNode joinRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "SrcJoinings");
                foreach (string joinField1 in this.Src1_Src2_Joinings.Keys)
                {
                    XmlNode joinNode = XmlDataUtil.AddElement(ref xDoc, joinRootNode, "SrcJoining");
                    XmlDataUtil.UpdateAttribute(ref xDoc, joinNode, "SrcField1", joinField1);
                    XmlDataUtil.UpdateAttribute(ref xDoc, joinNode, "SrcField2", this.Src1_Src2_Joinings[joinField1]);
                }
            }

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "LinkScoreField", this.LinkScoreFieldInTargetTable);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SkipUpdateExistingData",
                                        this.SkipUpdateExistingData.ToString());

            return xNode;
        }
    }
}
